//
//      Copyright 20E Hengda Xiao 224080
//
//      Millionare
//
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//
//      04.05.2011


#include "gameplay.h"
#include "gamesystem.h"

using std::cin;
using std::cout;
using std::endl;

const int ELEVEN = 11;
const int TWELEVE = 12;
const int ONEMILLION = 1000000;
const int TWELVEFIVE = 125000;
const int THREETHOUSAND = 3000;


//Construction function of gameplay and create a question system for the
//game system. A question part has been included.

GamePlay::GamePlay(char **argv):pHead(NULL),random_quest_play(),ffVec(),
                                playNum(1),Quit(false),quit_SGame(false)
{
    questionSys = new GameSystem(argv);
    DoChoice_Play();
}




//set all pointers to NULL when deconstruction

GamePlay::~GamePlay()
{
    delete questionSys;
    questionSys = NULL;
    delete pHead;
    pHead =NULL;
}



//to show the menu of the game play system

void GamePlay::Menu_Play()
{
    cout << "\n[1] Start Game" << endl;
    cout << "[2] Instructions" << endl;
    cout << "[3] Player Statistics" << endl;
    cout << "[4] Question option" << endl;
    cout << "[5] Quit" << endl;
    cout << "\nYour choice:";
    string strChoice;
    cin >> strChoice;
    while(!questionSys->StringCheck(strChoice))
    {
        cout << "\nMust enter the number!" << endl;
        cout << "Please enter your choice again!" << endl;
        cout << "Your choice:";
        cin >> strChoice;
    }
    std::stringstream sstream_choice(strChoice);
    sstream_choice >> choice;
}



//According to the different case the player want to play,
//to run the different functions

void GamePlay::DoChoice_Play()
{
    while(!Quit){
        Menu_Play();
        switch(choice)
        {
        case 1:
            DoChoice_Play_Start();
            break;
        case 2:
            Instructions();
            break;
        case 3:
            Statistics();
            break;
        case 4:
            questionSys->DoChoice_Quest();
            break;
        case 5:
            Quit = true;
            cout << "Exiting..." << endl;
            break;
        default:
            cout << "Invalid command! " << endl;
            break;
        }
    }
}



//Print the which level the player is in right now.
//Using two for loops to display the prize part, there
//is regular pattern among the whole prize number. That
//is the most conventinet way to display the prize list
//dynamically

void GamePlay::PrintPrize()
{
    int maxPrize = ONEMILLION;
    int level = pCur->getLevel();
    cout << "Lifelines" << endl;
    cout <<"\n" << pCur->getFFTimes() << "     [f] Fifty-Fifty" << endl;
    cout << "\n**************************************" << endl;
    cout << "Levels and Prizes" << endl;
    cout << endl;
    for(int i = TWELEVE; i >= 10; i--){
        if(i == level){
            cout << ">   " << i << "    $" << maxPrize << endl;
            curPrize = maxPrize;
        }
        else{
            cout << "    " << i << "    $" << maxPrize << endl;
        }
        maxPrize = maxPrize / 2;
    }
    maxPrize = TWELVEFIVE;
    for(int i = 9; i >= 1; i--){
        if(i == level){
            cout << ">   " << i << "     $" << maxPrize << endl;
            curPrize = maxPrize;
        }
        else{
        cout << "    " << i << "     $" << maxPrize << endl;
        }
        if(i == 9){
            maxPrize = (maxPrize + THREETHOUSAND)/2;
        }
        else{
        maxPrize = maxPrize / 2;
        }
    }
    cout << "**************************************" << endl;
}





//To display the sub menu of start game function

void GamePlay::Menu_Play_Start()
{
    cout << "[1] Select Player" << endl;
    cout << "[2] New Plyaer" << endl;
    cout << "[3] Back to Main Menu" << endl;
    cout << "\nYour choice:";
    string strChoice;
    cin >> strChoice;
    while(!questionSys->StringCheck(strChoice))
    {
        cout << "\nMust enter the number!" << endl;
        cout << "Please enter your choice again!" << endl;
        cout << "Your choice:";
        cin >> strChoice;
    }
    std::stringstream sstream_choice(strChoice);
    sstream_choice >> choice;
}




//According the player's input to judge which case
//they want to play.


void GamePlay::DoChoice_Play_Start()
{
    if(questionSys->GetQuestRdy()){
        quit_SGame = false;
        while(!quit_SGame){
            Menu_Play_Start();
            switch(choice)
            {
            case 1:
                SelectPlayer();
                break;
            case 2:
                CreatPlayer();
                RunGame();
                break;
            case 3:
                quit_SGame = true;
                break;
            default:
                cout << "Error! " << endl;
                break;
            }
        }
    }
    else{
        cout << "Question repository is under construction! Please return later to play the game. " << endl;
        DoChoice_Play();
    }
}





//The slect player function, I use dynamic linked list here,
//the function will go through the whole linked list and to
//find the player whose ID is same with user input ID. It
//will go through the linked list from head to end until it
//find the right player, if no player is founded it will display
//player doesn't exist


void GamePlay::SelectPlayer()
{
    if(pHead == NULL){
        cout << "There is no player registered. Create new player." <<endl;
        CreatPlayer();
        RunGame();
    }
    else{
        DisplayPlayer();
        int player_choice;
        cout << "\nChoose Player(ID): ";
        string strChoice;
        cin >> strChoice;
        while(!questionSys->StringCheck(strChoice))
        {
            cout << "\nMust enter the number!" << endl;
            cout << "Please enter your choice again!" << endl;
            cout << "Your choice:";
            cin >> strChoice;
        }
        std::stringstream sstream_choice(strChoice);
        sstream_choice >> player_choice;
        pCur = pHead;
        while(pCur){//Go through the whole linked list from beginning
            if(pCur->getId()== player_choice){
             RunGame();
             break;
            }
            else if(pCur->getNext() == NULL){
                cout << "Player doesn't exist!" << endl;
                SelectPlayer();
                break;
            }
            pCur = pCur->getNext();
        }
    }
}



//The create player function. Also use dynamic linked list here,
//it will first check if the head poniter of the linked list is NULL
//or not. If the header is NULL it will create the player as the first node,
//otherwise, it will inster the player node to the end of the linked list


void GamePlay::CreatPlayer()
{
    string playerName;
    if(pHead == NULL){//The first node case
        pCur = new Player;
        cout << "Enter Player Name:";
        cin.ignore();
        getline(cin,playerName);
        pCur->setName(playerName);
        pCur->setId(playNum);
        pCur->setNext(NULL);
        pHead = pCur;
        if(pCur->getName()== ""){
            delete pCur;
            pHead = NULL;
        }
    }
    else{//Not the first node case, insert the node to end
        pCur = pHead;
        while(pCur->getNext() != NULL){
            pCur = pCur->getNext();
        }
            pNew = new Player;
            playNum++;
            cout << "Enter Player Name:";
            cin.ignore();
            getline(cin,playerName);
            pNew->setName(playerName);
            pNew->setId(playNum);
            pNew->setNext(NULL);
            pCur->setNext(pNew);
                if(pNew->getName()== ""){
                delete pNew;
                pCur->setNext(NULL);
                }
    }
}




//Display all player names. Just go thourgh the whole linked list

void GamePlay::DisplayPlayer()
{
    pCur = pHead;
    while(pCur){
        cout <<"[" << pCur->getId() << "]" << pCur->getName() << endl;
        pCur = pCur->getNext();
    }
}



//To start a new round of a player, it will first use the existed quesion
//system to generate a random question list for the player and initialize
//different attributes of the player then showing the przie part and question
//part

void GamePlay::RunGame()
{
    questionSys->GenerateQuest();
    pCur->setQuit(false);
    pCur->setLevel(1);
    pCur->setCorrectNum(0);
    pCur->setMoney(0);
    while(!pCur->getQuit()){
        PrintPrize();
        random_quest_play = questionSys->GetRanQuest();
        PrintRanQuest();
        Judgement();
    }
}



//Get the different level quesion from the random question vector
//made by the question part

void GamePlay::PrintRanQuest()
{
    for(unsigned int i = 0; i < random_quest_play.size(); i++){
        if(pCur->getLevel() == random_quest_play[i]->getLevel()){
             curQuest = i;
             cout << "**************************************" <<endl;
             cout << "Level " << random_quest_play[i]->getLevel() << endl;
             cout << "Question " << i + 1 <<endl;
             cout << endl;
             cout << "Description:" << endl;
             cout << random_quest_play[i]->getDescription() << endl;
             cout << "[A] " << random_quest_play[i]->getChoiceA() <<endl;
             cout << "[B] " << random_quest_play[i]->getChoiceB() <<endl;
             cout << "[C] " << random_quest_play[i]->getChoiceC() <<endl;
             cout << "[D] " << random_quest_play[i]->getChoiceD() <<endl;
             cout << "\n**************************************" <<endl;
             cout << "[t] Take money and end the game" << endl;
             cout << "\nYour choice:";
        }
    }
    string ansStr;
    cin >> ansStr;
    pCur->setAnswer(ansStr);
}



//For the judgement part it will first check if the player input the corresponding
//letter. And in the coressponding letter, it will run the corresponding function
//to go deeper judgement.
//In fifty fifty case, it will first check if the player still has enough chances and then
//it will check if the player has already uesed one chance for this problem
//In take moeny away case, it just set some player's attributes to originial and end round
//If the cases are not belong to any of the above cases, system will think the player input
//the answer for this problem and compare to correct answer of this question.If it is correct
//the game will contiune in the while loop, otherwise, it will end the round

void GamePlay::Judgement()
{
    int again_choice;
    while(pCur->getAnser() != "f" && pCur->getAnser() != "t" &&pCur->getAnser() != "A" &&
          pCur->getAnser() != "B" &&pCur->getAnser() != "C" &&pCur->getAnser() != "D"){
        cout << "Invalid command." << endl;
        cout << "You must enter the corresponding letter.\n" << endl;
        PrintRanQuest();
    }
    if(pCur->getAnser() == "f"){
        if(pCur->getFFTimes() > 0){//if the player still has enough FF chaces
            if(!pCur->GetffFlag()){//if the player never use FF chance for this question
                FiftyFifty();
            }
            else{
                cout << "You have already use one Fifty-Fifty chance for this problem." << endl;
                PrintRanQuest_FF_Original();
                string ansStr;
                cin.ignore();
                cin >> ansStr;
                pCur->setAnswer(ansStr);
                Judgement();
            }
        }
        else{
               cout << "You do not have Fifty-Fifty chance any more !" << endl;
               PrintPrize();
               PrintRanQuest();
               Judgement();
        }
    }
    else if(pCur->getAnser() == "t"){//take the money away
        cout << "You leave the game with " << pCur->getMoney() << "!" << endl;
        pCur->setQuit(true);
        quit_SGame = true;
        pCur->SetffFlag(false);
        pCur->setFFTimes(3);
    }
    else if(pCur->getAnser() == random_quest_play[curQuest]->getCorrectAns()){
        pCur->SetffFlag(false);
        cout << "Correct!" << endl;
        cout << "Congratulations! You won " << curPrize << " !" << endl;
        pCur->setLevel(pCur->getLevel() + 1);
        pCur->setCorrectNum(pCur->getCorrectNum() + 1);
        pCur->setMoney(curPrize);
        if(checkHighestLevel()){//to check if the player has already reached
                                //the highest level
            pCur->setFFTimes(3);
            cout << "[1] Play again" << endl;
            cout << "[2] Return to main menu" << endl;
            cout << "Your choice:";
            cin >> again_choice;
            switch(again_choice){
            case 1:
                RunGame();
                break;
            case 2:
                pCur->setQuit(true);
                quit_SGame = true;
                break;
            default:
                cout << "Invalid command" << endl;
                break;
            }
        }
        }
        else{//If the answer is wrong
            pCur->SetffFlag(false);
            cout << "Incorrect!" << endl;
            cout << "You leave the game with " << pCur->getMoney() << "!" << endl;
            cout << "[1] Play again" << endl;
            cout << "[2] Return to main menu" << endl;
            cout << "Your choice:";
            cin >> again_choice;
            switch(again_choice){
            case 1:
                RunGame();
                break;
            case 2:
                pCur->setQuit(true);
                quit_SGame = true;
                break;
            default:
                cout << "Invalid command" << endl;
                break;
            }
        }
}




//In the FF case, it will make a number flag to each different correct answer
//and then random a number for the other wrong answers make up a new vector which
//only include two choices for the player.

void GamePlay::FiftyFifty()
{
    unsigned int size = ffVec.size();
    if(size !=0 ){
        ffVec.clear();
    }
    string correctAns = random_quest_play[curQuest]->getCorrectAns();
    if(correctAns == "A"){
        ffAns1 = 1;
    }
    else if(correctAns == "B"){
        ffAns1 = 2;
    }
    else if(correctAns == "C"){
        ffAns1 = 3;
    }
    else if(correctAns == "D"){
        ffAns1 = 4;
    }
    RandomNumber();
    if(ffAns1 < ffAns2 ){//To show the answers in a correct sequence
        ffVec.push_back(ffAns1);
        ffVec.push_back(ffAns2);
    }
    else{
        ffVec.push_back(ffAns2);
        ffVec.push_back(ffAns1);
    }
    PrintRanQuest_FF();
    string ansStr;
    cin.ignore();
    cin >> ansStr;
    pCur->setAnswer(ansStr);
    pCur->SetffFlag(true);
    Judgement();
}




//Random a number, just a way to select a answer from the wrong
//answers. if the random number flag equals the correct one, it
//will random again until get a different number flag.

void GamePlay::RandomNumber()
{
    int randomNum = 0;
    int upperBound = 4;
    std::srand(std::time(NULL));
    randomNum = std::rand()%upperBound + 1;
    while(randomNum == ffAns1){
        std::srand(std::time(NULL));
        randomNum = std::rand()%upperBound + 1;
    }
    if(randomNum == 1){
        ffAns2 = 1;
    }
    else if(randomNum == 2){
        ffAns2 = 2;
    }
    else if(randomNum == 3){
        ffAns2 = 3;
    }
    else if(randomNum == 4){
        ffAns2 = 4;
    }

}




//To print the has been used FF chance question from another vector

void GamePlay::PrintRanQuest_FF()
{
    if(pCur->getFFTimes() <= 0){
        PrintPrize();
        PrintRanQuest();
    }
    else{
        pCur->setFFTimes(pCur->getFFTimes()- 1);
        PrintPrize();
        cout << "**************************************" <<endl;
        cout << "Level " << random_quest_play[curQuest]->getLevel() << endl;
        cout << "Question " << curQuest + 1 <<endl;
        cout << endl;
        cout << "Description:" << endl;
        cout << random_quest_play[curQuest]->getDescription() << endl;
        for(unsigned int i = 0; i < ffVec.size(); i++){
            switch(ffVec[i]){
            case 1:
                cout << "[A] " << random_quest_play[curQuest]->getChoiceA() << endl;
                break;
            case 2:
                cout << "[B] " << random_quest_play[curQuest]->getChoiceB() << endl;
                break;
            case 3:
                cout << "[C] " << random_quest_play[curQuest]->getChoiceC() << endl;
                break;
            case 4:
                cout << "[D] " << random_quest_play[curQuest]->getChoiceD() << endl;
                break;
            default:
                break;
            }
        }
        cout << "\n**************************************" <<endl;
        cout << "[t] Take money and end the game" << endl;
        cout << "\nYour choice:";
    }
}




//If the player does not have FF chance any more, it will still show the
//original answers

void GamePlay::PrintRanQuest_FF_Original()
{
    PrintPrize();
    cout << "**************************************" <<endl;
    cout << "Level " << random_quest_play[curQuest]->getLevel() << endl;
    cout << "Question " << curQuest + 1 <<endl;
    cout << endl;
    cout << "Description:" << endl;
    cout << random_quest_play[curQuest]->getDescription() << endl;
    for(unsigned int i = 0; i < ffVec.size(); i++){
        switch(ffVec[i]){
        case 1:
            cout << "[A] " << random_quest_play[curQuest]->getChoiceA() << endl;
            break;
        case 2:
            cout << "[B] " << random_quest_play[curQuest]->getChoiceB() << endl;
            break;
        case 3:
            cout << "[C] " << random_quest_play[curQuest]->getChoiceC() << endl;
            break;
        case 4:
            cout << "[D] " << random_quest_play[curQuest]->getChoiceD() << endl;
            break;
        default:
            break;
        }
    }
    cout << "\n**************************************" <<endl;
    cout << "[t] Take money and end the game" << endl;
    cout << "\nYour choice:";
}




//Due to the instruction for the game is quite long, using a text
//file outside and read them from the text file then print them all
//out

void GamePlay::Instructions()
{
    string tempStr;
    std::ifstream inFile;
    inFile.open("instructions.txt");
    cout << "\n\n\n";
    while(!inFile.eof()){
        getline(inFile,tempStr);
        cout << tempStr << endl;
    }
    inFile.close();
    cout << "\n\n\n";
}



//Just go through the wholw linked list and show the different
//attributes of  player

void GamePlay::Statistics()
{
    pCur = pHead;
    cout << "Player Statistics:" << endl;
    cout << endl;
    cout << "Name" << "     " << endl;
    if(pCur == NULL){
        cout << "Exsit no players." << endl;
    }
    else{
        while(pCur){
            cout << pCur->getName() << "     $" << pCur->getMoney() << endl;
            pCur = pCur->getNext();
        }
    }
}




//Check if the player reach the highest level the game.

bool GamePlay::checkHighestLevel()
{
    if(pCur->getLevel() > TWELEVE){
        return true;
    }
    else{
        return false;
    }
}
